#include "global.h"
#define LOG_TAG TAG_COMCU
#include "co_heartbeat_log.h"
#include "FreeRTOS.h"
#include "task.h"
#include "co_heartbeat.h"
#include "utils/utils_crc16.h"
#include "cmsis_os2.h"
#include "bsp.h"
#include "bsp_uart.h"
#include "comm/ota.h"
#include "misc/hwmisc.h"
#include "mmgr/include/mmgr_modem.h"
#include "misc/version.h"
#include "misc/misc_server.h"
#include "aadl/public.h"
#include "aadl/include/aadl/flash.h"
#include "service/include/port/swei_wrapper.h"
#include "flash/protocol_params/protocol_params.h"
#include "flash/flash_main.h"
#include "misc/task_misc.h"
#include <stdio.h>
#include "utils/utils_timer.h"
#include "misc/misc_api.h"
#include "misc/misc_server.h"
#include "service/include/swei_package.h"
#include "drivers/modem/qlmodem/task_modem.h"
#include "mmgr/include/mmgr_pdp.h"
#include "mmgr/include/mmgr_misc.h"
#include "mmgr/include/mmgr_modem.h"
#include "misc/version.h"
#include "task_gnss.h"
#include "misc/hwmisc.h"
#include "service/include/swei_login.h"
#include "service/include/swei_active.h"
#include "misc/rtc_app.h"
#include "misc/misc_system.h"
#include "gnss_power_mgr.h"
#include "bsp_comm.h"
/**************************************************VARIABLE DECLRATION*****************************************************************************/
typedef void (*cb_t)(bool);
/* 消息节点 */
typedef struct {
    uint8_t *data;
    uint32_t len;
    int32_t timeout;
    uint8_t retry;
    cb_t cb;
    struct list_head list;
} msg_node_t;
/* 发送链表 */
static struct list_head msg_list = LIST_HEAD_INIT(msg_list);

/* 全局变量集合 */
typedef struct 
{
    bool is_comm_task_idle;
    uint8_t step;
    uint32_t time;
    uint8_t run_times;
    utils_time_t timer;
}comm_info_t;
static comm_info_t comm_info = {
    .step = 0,
    .is_comm_task_idle = true,
};

static TaskHandle_t cohb_handle = NULL;
/* 信号量保护 */
static SemaphoreHandle_t    comm_semaphore;          

/* 电控版本 */
static version_t econ_version = {0};
/* 仪表版本 */
static version_t co_version = {0};
/* 电池版本 */
static version_t batt_version = {0};
/* 蓝牙版本 */
static version_t bt_version = {0};
/* eeprom版本 */
static char eeprom_version[6] = {0};
/* 电池容量信息 */
batt_volume_info_t batt_volume_info = {0};
/* 电池运行状态信息 */
batt_stat_t batt_stat = {0};
/* 电机控制器状态信息1 */
econ_info1_t econ_stat_info1 = {0};
/* 电机控制器状态信息2 */
econ_info2_t econ_stat_info2 = {0};
/* 电机控制器状态信息3 */
econ_info3_t econ_stat_info3 = {0};
/* 电机控制器信息1（暂时不想改这个变量名） */
co_motor_ctrl_info_1_t co_motor_ctrl_info_1 = {0};
/* 电机控制器信息2 */
electric_vehicle_info2_t electric_vehicle_info2 = {0};
/* 车端系统参数 */
bike_system_info_t bike_system_info = {0};
/* 充电器交互状态 */
charger_info_t charger_info = {0};
/* 电控故障码 */
co_fault_code_t econ_fault_code = {0};
/* 电池故障码 */
co_fault_code_t batt_fault_code = {0};
/* 备用电池故障码 */
co_fault_code_t backup_batt_fault_code = {0};
/* 充电器故障码 */
co_fault_code_t charger_fault_code = {0};
/* 电子锁故障码 */
co_fault_code_t elock_fault_code = {0};
/* 小电池充电状态 */
lbatt_chg_stat_t lbatt_chg_stat = {0};
/* 电池序列号 */
static int8_t batt_sn[32] = {0};
/* 副电池序列号 */
static int8_t backup_batt_sn[32] = {0};
/* 电机序列号 */
static int8_t econ_sn[32] = {0};
/* 仪表序列号 */
static int8_t co_sn[32] = {0};
/* 蓝牙地址 */
static uint8_t ble_mac[BLE_MAC_LEN] = {0};
/* 蓝牙连接状态 */
int8_t ble_status = 0;

/* 最后一次心跳包接收时间，用于判断仪表开关机 */
unsigned int co_heartbeat_last_recv_tick = 0;
uint16_t temp_tbl[128] = {0};
uint8_t cfg_trig_heartbeat = 0;
co_status_info_t co_status_info = {0};
batt_run_status_info_t batt_run_status_info[BATT_TYPE_MAX] = {0};
batt_charge_status_info_t batt_charge_status_info[BATT_TYPE_MAX] = {0};
batt_capacity_info_t batt_capacity_info[BATT_TYPE_MAX] = {0};
batt_cell_volt_info_t batt_cell_volt_info[BATT_TYPE_MAX] = {0};
batt_status_info_t batt_status_info[BATT_TYPE_MAX] = {0};
li_batt_status_info_t li_batt_status_info = {0};
co_lock_status_t co_lock_status = {
    .status = 0xFF
};
co_auth_status_t co_auth_status = {0};
exbatt_stat_t exbatt_stat = {
    .supply = 1,
};

extern uint32_t tbox_ota_flag;

/**************************************************FUNCTION DECLRATION*****************************************************************************/
extern void Error_Handler(void);
extern const char *mmgr_subversion_get(void);

//static void cfg_parse(uint8_t id, uint8_t* payload, uint16_t len);
void cfg_parse(uint8_t id, uint8_t* payload, uint16_t len);
void co_key_add(uint16_t *key, uint16_t len);
static void co_comm_task(void *param);
static int co_data_send(uint8_t method, uint8_t class, uint8_t id, uint8_t *data, uint16_t cnt, cb_t cb);
static uint8_t co_data_parse(uint8_t data);
static void hb_parse(uint8_t* data, uint16_t len);
static void poll_parse(uint8_t* data, uint16_t len);
static void co_send_ack(uint16_t msg_type);
static void co_send_nack(uint16_t msg_type, uint8_t err_code);
static bool co_hearbeat_add(uint16_t key);
static void co_hearbeat_del(void);
static int ota_read(void *data, int len);
static int ota_write(void *data, int len);
// static uint8_t co_data_recv(uint8_t data);
static void data_recv_process(uint8_t data);
static void data_send_process(void);
static int msg_enqueue(uint8_t *data, uint32_t data_len, int32_t timeout, uint8_t retry, cb_t cb);
static void first_cmd_dequeue(bool is_rest);
static void parse_hook(void);
static void sync_econ_version_from_comcu(void);
static void sync_eeprom_version_from_comcu(void);
static void sync_sn_from_comcu();
static void sync_co_version_from_comcu();
static void sync_bt_version_from_comcu();
static void sync_econ_version_from_comcu();
static void sync_eeprom_version_from_comcu();
static void sync_blemac_from_comcu();
static void sync_batt_version_from_comcu();
static void data_send_process();
static void first_cmd_dequeue(bool is_rest);
static void data_send_process(void);
static void data_recv_process(uint8_t data);

static int msg_enqueue(uint8_t *data, uint32_t data_len, int32_t timeout, uint8_t retry, cb_t cb);
static void send_heartbeat(void);
static void sync_pwr_cb(bool is_timeout);

/**
 * @brief 释放信号量
 * 
 */
static void commSemaphoreGive(void)
{
    xSemaphoreGive(comm_semaphore);
}


/**
 * @brief 获取信号量
 * 
 * @return -EBUSY:信号量被占用
 *         -ENOMEN:内存不足，信号量无法创建
 *         0:成功
 */
static int commSemaphoreTake(void)
{
    if (NULL == comm_semaphore) {
        taskENTER_CRITICAL();
        if (NULL == comm_semaphore)
            comm_semaphore = xSemaphoreCreateCounting(1, 1);
        taskEXIT_CRITICAL();
    }
    if (NULL == comm_semaphore)
        Error_Handler();
    if (pdFALSE == xSemaphoreTake(comm_semaphore, portMAX_DELAY))
        return -EBUSY;
    return 0;
}


uint16_t get(uint8_t *p_data, uint16_t len)
{
    uint8_t temp[3] = {0x01, 0x02, 0x03};
    if(NULL == p_data) {
        return 0;
    } else {
        memcpy(p_data, temp, sizeof(temp));
    }

    return sizeof(temp);
}


void econ_version_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    if (0 != data[0] || 0 != data[1] || 0 != data[2] || 0 != data[3])
        snprintf(econ_version.soft_version, sizeof(econ_version.soft_version), "V%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
    if (0 != data[4] || 0 != data[5] || 0 != data[6] || 0 != data[7])
        snprintf(econ_version.hw_version, sizeof(econ_version.hw_version), "V%d.%d.%d.%d", data[4], data[5], data[6], data[7]);
    log_d("econ_soft_version is:%s, econ_hw_version is:%s", econ_version.soft_version, econ_version.hw_version);
    commSemaphoreGive();
}


void co_version_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    /* 如果不是beta版本，不带BXX */
    if (data[3] == 0)
        snprintf(co_version.soft_version, sizeof(co_version.soft_version), "DA35D1C10_CO_R%02dA%02dV%02d", data[0], data[1], data[2]);
    else 
        snprintf(co_version.soft_version, sizeof(co_version.soft_version), "DA35D1C10_CO_R%02dA%02dV%02dB%02d", data[0], data[1], data[2], data[3]);
    commSemaphoreGive();
}


void batt_version_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    if (0 != data[0] || 0 != data[1] || 0 != data[2] || 0 != data[3])
        snprintf(batt_version.soft_version, sizeof(batt_version.soft_version), "V%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
    if (0 != data[4] || 0 != data[5] || 0 != data[6] || 0 != data[7])
        snprintf(batt_version.hw_version, sizeof(batt_version.hw_version), "V%d.%d.%d.%d", data[4], data[5], data[6], data[7]);
    log_d("batt_soft_version is:%s, batt_hw_version is:%s", batt_version.soft_version, batt_version.hw_version);
    commSemaphoreGive();
}


void ble_version_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    /* 如果不是beta版本，不带BXX */
    if (data[3] == 0)
        snprintf(bt_version.soft_version, sizeof(bt_version.soft_version), "DA35D1C10_BT_R%02dA%02dV%02d", data[0], data[1], data[2]);
    else 
        snprintf(bt_version.soft_version, sizeof(bt_version.soft_version), "DA35D1C10_BT_R%02dA%02dV%02dB%02d", data[0], data[1], data[2], data[3]);    
    commSemaphoreGive();
}


void batt_seqnum_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    memcpy(batt_sn, data, len);
    commSemaphoreGive();
    // log_d("batt sn is %s", (char *)batt_sn);
}
void backup_batt_seqnum_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    memcpy(backup_batt_sn, data, len);
    commSemaphoreGive();
    // log_d("backup batt sn is %s", (char *)backup_batt_sn);
}
void econ_seqnum_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    memcpy(econ_sn, data, len);
    commSemaphoreGive();
    // log_d("econ sn is %s", (char *)econ_sn);
}
void co_seqnum_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    memcpy(co_sn, data, len);
    commSemaphoreGive();
}

void co_cust_seqnum_update(uint8_t *data, uint16_t len)
{
    if(len > 0) {
        tbox_clr_sn();
        tbox_set_sn((char *)data);
    }
}
void emu_info1_update(uint8_t *data, uint16_t len)
{
    int16_t value;

    commSemaphoreTake();
    co_motor_ctrl_info_1.motor_temp_valid = data[1] & 0x80;
    value = ((data[1] & 0x7F) << 8) + data[0];
    co_motor_ctrl_info_1.motor_temp = (value - 16384) * 0.1f;  //0.1℃
    // log_d("motor_temp:%f\r\n", co_motor_ctrl_info_1.motor_temp);

    co_motor_ctrl_info_1.ctrl_temp_valid = data[3] & 0x80;
    value = ((data[3] & 0x7F) << 8) + data[2];
    co_motor_ctrl_info_1.ctrl_temp = (value - 16384) * 0.1f;   //0.1℃

    co_motor_ctrl_info_1.current_valid = data[5] & 0x80;
    value = ((data[5] & 0x7F) << 8) + data[4];
    co_motor_ctrl_info_1.current = value * 0.01f;              //0.01A

    co_motor_ctrl_info_1.speed_valid = data[7] & 0x80;
    value = ((data[7] & 0x7F) << 8) + data[6];
    co_motor_ctrl_info_1.speed = value * 0.01f;                //0.01Km/h
    commSemaphoreGive();


}
void emu_info2_update(uint8_t *data, uint16_t len)
{
    int16_t value = 0;

    commSemaphoreTake();
    electric_vehicle_info2.soc_is_valid = data[0] & 0x80;
    electric_vehicle_info2.soc = data[0] & 0x7F;

    electric_vehicle_info2.pwr_lvl_is_valid = data[1] & 0x80;
    electric_vehicle_info2.pwr_lvl = data[1] & 0x7F;

    electric_vehicle_info2.engery_consumption_is_valid = data[3] & 0x80;
    value = ((data[3] & 0x7F) << 8) + data[2];
    electric_vehicle_info2.engery_consumption = value;

    electric_vehicle_info2.remain_range_is_valid = data[5] & 0x80;
    value = ((data[5] & 0x7F) << 8) + data[4];
    electric_vehicle_info2.remain_range = value * 0.1f;             /* 0.1Km */

    electric_vehicle_info2.single_range_is_valid = data[7] & 0x80;
    value = ((data[7] & 0x7F) << 8) + data[6];
    electric_vehicle_info2.single_range = (float)value * 0.1f;      /* 0.1Km */   
    commSemaphoreGive();
}
void bike_system_info_update(uint8_t *data, uint16_t len)
{
    int16_t value = 0;

    commSemaphoreTake();

    bike_system_info.is_circumference_valid = data[2] & 0x80;
    value = ((data[2] & 0x7F) << 8) + data[1];
    bike_system_info.wheel_circumference = value * 0.1f;

    bike_system_info.is_wheel_diameter_valid = data[4] & 0x80;
    value = ((data[4] & 0x7F) << 8) + data[3];
    bike_system_info.wheel_diameter = value * 0.1f;
    log_d("wheel_diameter:%f\r\n", bike_system_info.wheel_diameter);

    bike_system_info.is_speed_limit_valid = data[6] & 0x80;
    value = ((data[6] & 0x7F) << 8) + data[5];
    bike_system_info.speed_limit = (uint8_t)value * 0.01f;  

    bike_system_info.cfg_pwroff = data[7];

    commSemaphoreGive();
}
void econ_stat_info1_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    memcpy(&econ_stat_info1, data, len);
    commSemaphoreGive();
    // log_d("econ_stat_info1 update, motor_speed:%d", econ_stat_info1.motor_speed);
}
void econ_stat_info2_update(uint8_t *data, uint16_t len)
{
    int16_t value = 0;

    commSemaphoreTake();

    value = ((data[2] & 0x7F) << 8) + data[1];
    econ_stat_info2.single_rided_time = value * 2;

    econ_stat_info2.throttle_volt = data[3] * 0.1f;

    value = ((data[5] & 0x7F) << 8) + data[4];
    econ_stat_info2.bus_cur = value * 0.1f;

    value = ((data[7] & 0x7F) << 8) + data[6];
    econ_stat_info2.bus_volt = value * 0.1f;

    commSemaphoreGive();
}
void emu_stat_info3_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();

    econ_stat_info3.total_range = (data[2] | (data[3] << 8) | (data[4] << 16) | (data[5] << 24)) * 0.01;

    econ_stat_info3.econ_mode = data[6];

    econ_stat_info3.econ_work_stat = data[7];

    commSemaphoreGive();
}
void emu_eppr_vr_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    memcpy(eeprom_version, data, len);
    commSemaphoreGive();
}
void batt_capacity_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_capacity_info[main_batt].nominal_c_valid = data[1] & 0x80;
    batt_capacity_info[main_batt].nominal_capacity = data[0] + ((data[1] & 0x7F) << 8);
    batt_capacity_info[main_batt].full_c_valid = data[3] & 0x80;
    batt_capacity_info[main_batt].full_capacity = data[2] + ((data[3] & 0x7F) << 8);
    batt_capacity_info[main_batt].remain_c_valid = data[5] & 0x80;
    batt_capacity_info[main_batt].remain_capacity = data[4] + ((data[5] & 0x7F) << 8);
    batt_capacity_info[main_batt].is_soh_valid = data[6] & 0x80;
    batt_capacity_info[main_batt].soh = data[6] & 0x7F;
    batt_capacity_info[main_batt].is_soc_valid = data[7] & 0x80;
    batt_capacity_info[main_batt].soc = data[7] & 0x7F;
    commSemaphoreGive();
    // log_d("batt capacity info update, soc:%02x, soh:%02x, remain capacity:%d, full capacity:%d\r\n", batt_capacity_info[main_batt].soc, batt_capacity_info[main_batt].soh, batt_capacity_info[main_batt].remain_capacity, batt_capacity_info[main_batt].full_capacity);
}


void backup_batt_capacity_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_capacity_info[backup_batt].nominal_c_valid = data[1] & 0x80;
    batt_capacity_info[backup_batt].nominal_capacity = data[0] + ((data[1] & 0x7F) << 8);
    batt_capacity_info[backup_batt].full_c_valid = data[3] & 0x80;
    batt_capacity_info[backup_batt].full_capacity = data[2] + ((data[3] & 0x7F) << 8);
    batt_capacity_info[backup_batt].remain_c_valid = data[5] & 0x80;
    batt_capacity_info[backup_batt].remain_capacity = data[4] + ((data[5] & 0x7F) << 8);
    batt_capacity_info[backup_batt].is_soh_valid = data[6] & 0x80;
    batt_capacity_info[backup_batt].soh = data[6] & 0x7F;
    batt_capacity_info[backup_batt].is_soc_valid = data[7] & 0x80;
    batt_capacity_info[backup_batt].soc = data[7] & 0x7F;
    commSemaphoreGive();
}
void batt_run_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_run_status_info[main_batt].reserved = data[0];
    batt_run_status_info[main_batt].discharge_s_valid = data[1] & 0x80;
    batt_run_status_info[main_batt].discharge_status = data[1] & 0x40;
    batt_run_status_info[main_batt].temp_valid = data[3] & 0x80;
    batt_run_status_info[main_batt].temperature = data[2] + ((data[3] & 0x7F) << 8) - 16384;
    batt_run_status_info[main_batt].current_valid = data[5] & 0x80;
    batt_run_status_info[main_batt].current = data[4] + ((data[5] & 0x7F) << 8) - 16384;
    batt_run_status_info[main_batt].batt_v_valid = data[7] & 0x80;
    batt_run_status_info[main_batt].batt_voltage = (data[6] + ((data[7] & 0x7F) << 8));
    batt_run_status_info[main_batt].batt_voltage *= 0.01f;
    commSemaphoreGive();
    // log_d("batt_run_status_info update, batt_voltage:%f, temperature:%d\r\n", batt_run_status_info[main_batt].batt_voltage, batt_run_status_info[main_batt].temperature);
}


void backup_batt_run_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_run_status_info[backup_batt].reserved = data[0];
    batt_run_status_info[backup_batt].discharge_s_valid = data[1] & 0x80;
    batt_run_status_info[backup_batt].discharge_status = data[1] & 0x40;
    batt_run_status_info[backup_batt].temp_valid = data[3] & 0x80;
    batt_run_status_info[backup_batt].temperature = data[2] + ((data[3] & 0x7F) << 8) - 16384;
    batt_run_status_info[backup_batt].current_valid = data[5] & 0x80;
    batt_run_status_info[backup_batt].current = data[4] + ((data[5] & 0x7F) << 8) - 16384;
    batt_run_status_info[backup_batt].batt_v_valid = data[7] & 0x80;
    batt_run_status_info[backup_batt].batt_voltage = (data[6] + ((data[7] & 0x7F) << 8)) * 0.01;
    commSemaphoreGive();
}


void batt_charge_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_charge_status_info[main_batt].reserved = data[0];
    batt_charge_status_info[main_batt].fa_time_valid = data[2] & 0x80;
    batt_charge_status_info[main_batt].first_active_time = data[1] + ((data[2] & 0x7F) << 8);
    batt_charge_status_info[main_batt].lc_time_valid = data[4] & 0x80;
    batt_charge_status_info[main_batt].last_charge_interval = data[3] + ((data[4] & 0x7F) << 8);
    batt_charge_status_info[main_batt].charge_c_valid = data[6] & 0x80;
    batt_charge_status_info[main_batt].charge_cycle = data[5] + ((data[6] & 0x7F) << 8);
    batt_charge_status_info[main_batt].charge_s_valid = data[7] & 0x80;
    batt_charge_status_info[main_batt].charge_state = data[7] & 0x40;
    commSemaphoreGive();
    // log_d("charge_s_valid:%d, charge_state:%d", data[7] & 0x80, data[7] & 0x40);
}


void backup_batt_charge_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_charge_status_info[backup_batt].reserved = data[0];
    batt_charge_status_info[backup_batt].fa_time_valid = data[2] & 0x80;
    batt_charge_status_info[backup_batt].first_active_time = data[1] + ((data[2] & 0x7F) << 8);
    batt_charge_status_info[backup_batt].lc_time_valid = data[4] & 0x80;
    batt_charge_status_info[backup_batt].last_charge_interval = data[3] + ((data[4] & 0x7F) << 8);
    batt_charge_status_info[backup_batt].charge_c_valid = data[6] & 0x80;
    batt_charge_status_info[backup_batt].charge_cycle = data[5] + ((data[6] & 0x7F) << 8);
    batt_charge_status_info[backup_batt].charge_s_valid = data[7] & 0x80;
    batt_charge_status_info[backup_batt].charge_state = data[7] & 0x40;
    commSemaphoreGive();
}


void batt_cell_volt_info_update(uint8_t *data, uint16_t len)
{
    int16_t value = 0;
    int16_t index = 0;

    commSemaphoreTake();
    batt_cell_volt_info[main_batt].cell_cnt = len / 2;
    for(int i = 0; i < len/2; i++) {
        value = data[2*i] + (data[2*i+1] << 8);
        if (0 != value)
            batt_cell_volt_info[main_batt].cell_volt[index++] = value;
        else {
            batt_cell_volt_info[main_batt].cell_cnt--;
            continue;
        } 
    }
    commSemaphoreGive();
}
void backup_batt_cell_volt_info_update(uint8_t *data, uint16_t len)
{
    int16_t value = 0;
    int16_t index = 0;

    commSemaphoreTake();
    batt_cell_volt_info[backup_batt].cell_cnt = len / 2;
    for(int i = 0; i < len/2; i++) {
        value = data[2*i] + (data[2*i+1] << 8);   
        if (0 != value)     
            batt_cell_volt_info[backup_batt].cell_volt[index++] = value;
        else {
            batt_cell_volt_info[backup_batt].cell_cnt--;
            continue;            
        }
    }
    commSemaphoreGive();
}


void batt_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_status_info[main_batt].reserved = data[0] + (data[1] << 8);
    batt_status_info[main_batt].charge_remain_time = data[2] + (data[3] << 8);
    batt_status_info[main_batt].temp_min = data[4] + (data[5] << 8);
    batt_status_info[main_batt].temp_max = data[6] + (data[7] << 8);
    commSemaphoreGive();
}
void backup_batt_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_status_info[backup_batt].reserved = data[0] + (data[1] << 8);
    batt_status_info[backup_batt].charge_remain_time = data[2] + (data[3] << 8);
    batt_status_info[backup_batt].temp_min = data[4] + (data[5] << 8);
    batt_status_info[backup_batt].temp_max = data[6] + (data[7] << 8);
    commSemaphoreGive();
}
void lbatt_status_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    li_batt_status_info.charge_state = data[0];
    li_batt_status_info.batt_voltage = data[1] + (data[2] << 8);
    li_batt_status_info.soc = data[3];
    log_d("lbatt status info update, charge_state:%d, batt_voltage:%d, soc:%d\r\n", li_batt_status_info.charge_state, li_batt_status_info.batt_voltage, li_batt_status_info.soc);
    commSemaphoreGive();
    // log_d("lbatt status info update, charge_state:%d\r\n", data[0]);
}

/* 硬件故障掩码 */
#define HARD_FAULT_MASK     1 << 0
/* 充电器温度过高掩码 */
#define TEMP_MASK           1 << 1
/* 输入电压错误掩码 */
#define VOLT_MASK           1 << 2
/* 充电器关闭状态掩码 */
#define STAT_MASK           1 << 3
/* 通讯接收超时掩码 */
#define COMM_MASK           1 << 4
void charger_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    /* 留500ms作余量 */
    utils_time_countdown_ms(&charger_info.timer, CO_MCU_HB_INTERVAL + 500);
    charger_info.is_hard_fault = data[2] & HARD_FAULT_MASK;
    charger_info.is_high_temp = data[2] & TEMP_MASK;
    charger_info.is_volt_err = data[2] & VOLT_MASK;
    charger_info.is_close = data[2] & STAT_MASK;
    charger_info.is_comm_timeout = data[2] & COMM_MASK;

    charger_info.charge_temp = (uint8_t)data[3] * 0.1f;
    charger_info.charge_volt = (uint8_t)data[4] * 0.1f;  
    charger_info.charge_cur = (uint8_t)data[5] * 0.1f;

    log_d("charger info update, data[2] is %d\r\n", data[2]);
    
    commSemaphoreGive();
}
void elock_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    co_lock_status.status = data[0];
    log_d("elock status update, status:%d\r\n", data[0]);
    commSemaphoreGive();
}




void co_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    co_status_info.is_dipped_beam_valid = data[0] & 0x80;
    co_status_info.dipped_beam = data[0] & 0x7F;

    co_status_info.is_full_beam_valid = data[1] & 0x80;
    co_status_info.full_beam = data[1] & 0x7F;

    co_status_info.is_left_turn_valid = data[2] & 0x80;
    co_status_info.left_turn_indicator = data[2] & 0x7F;

    co_status_info.is_right_turn_valid = data[3] & 0x80;
    co_status_info.right_turn_indicator = data[3] & 0x7F;

    co_status_info.tail_light = data[6];
    co_status_info.rear_light = data[7];
    log_d("co_info_update success\r\n");
    commSemaphoreGive();
}


/* ！！心跳帧不包含该数据则表示没有任何故障 */
void econ_fault_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    econ_fault_code.num = len;

    memset(econ_fault_code.code, 0, FAULT_CODE_LEN);

    if (len > 0) {
        memcpy(econ_fault_code.code, data, len);
        for (int i = 0; i < len; i++)
            log_d("econ fault code%d:%d\r\n",i, data[i]);
    }

    commSemaphoreGive();
}


void batt_fault_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    batt_fault_code.num = len;

    memset(batt_fault_code.code, 0, FAULT_CODE_LEN);

    if (len > 0)
        memcpy(batt_fault_code.code, data, len);
        for (int i = 0; i < len; i++)
            log_d("batt fault code%d:%d\r\n",i, data[i]);

    commSemaphoreGive();
}


void backup_batt_fault_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    backup_batt_fault_code.num = len;

    memset(backup_batt_fault_code.code, 0, FAULT_CODE_LEN);

    if (len > 0)
        memcpy(backup_batt_fault_code.code, data, len);

        for (int i = 0; i < len; i++)
            log_d("backup batt fault code%d:%d\r\n",i, data[i]);
    commSemaphoreGive();
}


void charger_fault_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    charger_fault_code.num = len;

    memset(charger_fault_code.code, 0, FAULT_CODE_LEN);

    if (len > 0)
        memcpy(charger_fault_code.code, data, len);
    commSemaphoreGive();
}


void elock_fault_info_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    elock_fault_code.num = len;

    memset(elock_fault_code.code, 0, FAULT_CODE_LEN);

    if (len > 0) {
        memcpy(elock_fault_code.code, data, len);
        for (int i = 0; i < len; i++)
            log_d("elock fault code%d:%d\r\n",i, data[i]);
    }
    commSemaphoreGive();
}


void co_pwd_auth_update(uint8_t *data, uint16_t len)
{
    co_auth_status.status = data[0];
    log_d("co pwd auth update, co_auth_status:%d\r\n", data[0]);
    /* co_pwd_auth_update_hook */
}


void lbatt_chg_stat_update(uint8_t *data, uint16_t len)
{
    commSemaphoreTake();
    lbatt_chg_stat.total_chg_time = data[0] | data[1] << 8;
    lbatt_chg_stat.total_chg_cnt = data[2] | data[3] << 8 | data[4] << 16 | data[5] << 24;
    log_d("lbatt chg stat update, total charge times:%d, total charge time:%d\r\n", data[0] | data[1] << 8, data[2] | data[3] << 8 | data[4] << 16 | data[5] << 24);
    commSemaphoreGive();

    // log_d("lbatt chg stat update, total charge times:%d, total charge time:%d\r\n", data[0] | data[1] << 8, data[2] | data[3] << 8 | data[4] << 16 | data[5] << 24);
    // log_d("lbatt chg stat update, total charge times:%d, total charge time:%d\r\n", data[0] | data[1] << 8, data[2] | data[3] << 8 | data[4] << 16 | data[5] << 24);
}


void ble_mac_update(uint8_t *data, uint16_t len)
{
    int8_t buf = 0;
    commSemaphoreTake();
    for(int i = 0; i < len; i = i+2)
    {
        sscanf((char *)&data[i], "%02hhx", &buf);

        ble_mac[i/2] = buf;
    }
    commSemaphoreGive();
}
void ble_status_update(uint8_t *data, uint16_t len)
{
    /*  0：广播关闭
        1：广播开启
        2：仅连接
        3：已连接且已配对 */
    ble_status = data[0];
    log_d("ble status update, ble status:%d\r\n", ble_status);
}
void iot_fw_version_update(uint8_t *data, uint16_t len)
{
    //memcpy(iot_fw_ver.iot_ver, ((iot_fw_t *)data) -> iot_ver, sizeof(iot_fw_ver.iot_ver));
}
void iot_net_status_update(uint8_t *data, uint16_t len)
{

}
void iot_gnss_status_info_update(uint8_t *data, uint16_t len)
{

}
void iot_status_info_update(uint8_t *data, uint16_t len)
{

}
void iot_sim_info_update(uint8_t *data, uint16_t len)
{

}
void iot_alarm_info_update(uint8_t *data, uint16_t len)
{

}
void iot_instruct_conf_update(uint8_t *data, uint16_t len)
{

}
void iot_param_conf_update(uint8_t *data, uint16_t len)
{

}

void iot_sound_conf_update(uint8_t *data, uint16_t len)
{

}

void exbat_stat_update(uint8_t *data, uint16_t len)
{
    // log_i("co-mcu: supply is %d, switch_stat is %d", data[0], data[1]);
    commSemaphoreTake();
    memcpy(&exbatt_stat, data, len);
    commSemaphoreGive();
    // log_i("supply: %d, switch: %d", exbatt_stat.supply, exbatt_stat.switch_stat);
}


uint16_t econ_version_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &econ_version, len);
        commSemaphoreGive();

    }

    return len;
}


uint16_t co_version_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &co_version, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_version_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &batt_version, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t ble_version_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &bt_version, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_seqnum_get(uint8_t *p_data, uint16_t len)
{  
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)batt_sn, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t backup_batt_seqnum_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)backup_batt_sn, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t econ_seqnum_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, econ_sn, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t co_seqnum_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, co_sn, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t co_cust_seqnum_get(uint8_t *p_data, uint16_t len)
{
    return 0;
}

uint16_t emu_info1_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &co_motor_ctrl_info_1, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t emu_info2_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &electric_vehicle_info2, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t bike_system_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &bike_system_info, len);
        commSemaphoreGive();
    }
    
    return len;
}

uint16_t econ_stat_info1_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &econ_stat_info1, len);
        commSemaphoreGive();
    }
    
    return len;
}

uint16_t econ_stat_info2_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &econ_stat_info2, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t econ_stat_info3_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &econ_stat_info3, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t emu_eppr_vr_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, eeprom_version, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_capacity_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_capacity_info[main_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t backup_batt_capacity_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_capacity_info[backup_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_run_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_run_status_info[main_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t backup_batt_run_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_run_status_info[backup_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_charge_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_charge_status_info[main_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t backup_batt_charge_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_charge_status_info[backup_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_cell_volt_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_cell_volt_info[main_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t backup_batt_cell_volt_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_cell_volt_info[backup_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t batt_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_status_info[main_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t backup_batt_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&batt_status_info[backup_batt]), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t lbatt_status_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, (uint8_t *)(&li_batt_status_info), len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t charger_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &charger_info, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t elock_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &co_lock_status, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t co_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &co_status_info, len);
        commSemaphoreGive();
    }

    return len;
}


uint16_t econ_fault_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &econ_fault_code, len);
        commSemaphoreGive();
    }    
    return len;
}

uint16_t batt_fault_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &batt_fault_code, len);
        commSemaphoreGive();
    }    
    return len;
}


uint16_t backup_batt_fault_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &backup_batt_fault_code, len);
        commSemaphoreGive();
    }    
    return len;
}


uint16_t charger_fault_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &charger_fault_code, len);
        commSemaphoreGive();
    }    
    return len;
}


uint16_t elock_fault_info_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &elock_fault_code, len);
        commSemaphoreGive();
    }    
    return len;
}


uint16_t co_pwd_auth_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        *p_data = co_auth_status.status;
    }

    return len;
}

uint16_t lbatt_chg_stat_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &lbatt_chg_stat, len);
        commSemaphoreGive();
    }

    return len;
}


uint16_t ble_mac_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, ble_mac, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t ble_status_get(uint8_t *p_data, uint16_t len)
{
    if(NULL == p_data) {
        return 0;
    } else {
        *p_data = ble_status;
    }

    return len;
}


uint16_t iot_fw_version_get(uint8_t *p_data, uint16_t len) {
    iot_fw_t iot_fw_ver = {0};
    
    /* modem ver */
    sprintf((void *)iot_fw_ver.mdm_ver, "%s", (char *)mmgr_subversion_get());

    /* imei */
    sprintf((void *)iot_fw_ver.imei, "%s", mmgr_imei_get());

    /* iot quec sn */
    sprintf((void *)iot_fw_ver.iot_sn, "%s", misc_read_quec_sn());

    /* iot ver */
    iot_fw_ver.iot_ver[0] = atoi(BRANCH_VERSION + 1);
    iot_fw_ver.iot_ver[1] = atoi(MAJOR_VERSION + 1);
    iot_fw_ver.iot_ver[2] = atoi(MINOR_VERSION + 1);

    /* gps_ver */
    char gps_ver[GNSS_FW_VER_LEN + 1] = {0};
    qltask_gnss_firmware_version(gps_ver, sizeof(gps_ver));

    /* AG3335M_V3.2.2.AG3335_xxxxxxxx */

    strncpy((void *)iot_fw_ver.gps_ver, gps_ver, sizeof(iot_fw_ver.gps_ver));

    /* iot_hw */
    int hw_num = get_hw_verno();
    iot_fw_ver.iot_hw[0] = hw_num / 100;
    iot_fw_ver.iot_hw[1] = hw_num % 100;

    if(NULL == p_data) {
        return 0;
    } else {
        memcpy(p_data, &iot_fw_ver, len);
    }

    return len;
}


uint16_t iot_net_status_get(uint8_t *p_data, uint16_t len)
{
    iot_net_t iot_net = {0};

    commSemaphoreTake();
    /* sim valid */
    iot_net.sim_valid = mmgr_simcard_exist_get();

    /* net_status */
    iot_net.net_status = mmgr_pdp_status_get();

    /* csq */
    /* csq(1~31) already tranformed*/
    int rssi;
    if (0 == modem_get_signal_quality(&rssi, NULL)) { // modem_get_signal_quality(&rssi, NULL);
        iot_net.csq = (rssi > 128) ? 99 : rssi;
    } else {
        iot_net.csq = 99;
    }

    /* rat_state */
    int rat_state;
    modem_get_netreg_status(NULL, &rat_state);
    if (rat_state == NET_AUTO) {
        iot_net.rat_state = 0;   //auto
    } else if (rat_state == NET_2G) {
        iot_net.rat_state = 1;   //2G
    } else if ( (rat_state == NET_4G) || (rat_state == NET_EMTC) || (rat_state == NET_NBIoT) ) {
        iot_net.rat_state = 2;   //4G
    } else {
        iot_net.rat_state = 3;   //others
    }

    if(NULL == p_data) {
        commSemaphoreGive();
        return 0;
    } else {
        memcpy(p_data, &iot_net, len);
        commSemaphoreGive();
    }
    return len;
}


uint16_t iot_gnss_status_info_get(uint8_t *p_data, uint16_t len)
{
    iot_gnss_t iot_gnss = {0};

    struct fix_info gnss_info;
    struct sat_info gnss_sat;
    unsigned int count;

    commSemaphoreTake();

    get_last_gnss_info(&gnss_info);
    get_last_sat_info(&gnss_sat, &count);

    /* loc_status */
    iot_gnss.loc_status = (gnss_info.state == FIX_OK) ? true : false;

    /* gnss_num */
    iot_gnss.gnss_num = gnss_sat.count;
    memset(iot_gnss.gnss_cn, 0, GNSS_CN_LEN);
    int gnss_cout_min = gnss_sat.count < GNSS_CN_LEN ? gnss_sat.count : GNSS_CN_LEN;

    for(int i = 0; i < gnss_cout_min; i++) {
        iot_gnss.gnss_cn[i] = gnss_sat.sat[i].signal_strength;
    }

    if(NULL == p_data) {
        commSemaphoreGive();
        return 0;
    } else {
        memcpy(p_data, &iot_gnss, len);
        commSemaphoreGive();
    }

    return len;
}


uint16_t iot_status_info_get(uint8_t *p_data, uint16_t len)
{
    iot_status_t iot_status = {0};

    commSemaphoreTake();
    /* plat_conn_status */
    iot_status.plat_conn_status = swei_login_is_ok();

    /* active_status */
    iot_status.active_status = misc_get_active_state();

    if(NULL == p_data) {
        commSemaphoreGive();
        return 0;
    } else {
        memcpy(p_data, &iot_status, len);
        commSemaphoreGive();
    }

    return len;
}

uint16_t iot_sim_info_get(uint8_t *p_data, uint16_t len)
{
    iot_sim_t iot_sim = {0};

    commSemaphoreTake();

    /* iccid */
    strncpy((void *)iot_sim.iccid, mmgr_iccid_get(), sizeof(iot_sim.iccid));

    /* imsi */
    strncpy((void *)iot_sim.imsi, mmgr_imsi_get(), sizeof(iot_sim.imsi));

    if(NULL == p_data) {
        commSemaphoreGive();
        return 0;
    } else {
        memcpy(p_data, &iot_sim, sizeof(iot_sim) > len ? len : sizeof(iot_sim));
        commSemaphoreGive();
    }

    return len;
}

uint16_t iot_alarm_info_get(uint8_t *p_data, uint16_t len)
{
    uint8_t temp[7] = {0x01, 0x02, 0x03};
    if(NULL == p_data) {
        return 0;
    } else {
        memcpy(p_data, temp, len);
    }

    return len;
}

uint16_t iot_instruct_conf_get(uint8_t *p_data, uint16_t len) {
    uint8_t temp[VR_LEN] = {0x01, 0x02, 0x03};
    if(NULL == p_data) {
        return 0;
    } else {
        memcpy(p_data, temp, len);
    }

    return len;
}


uint16_t iot_sound_conf_get(uint8_t *p_data, uint16_t len) {
    uint8_t temp[VR_LEN] = {0x01, 0x02, 0x03};
    if(NULL == p_data) {
        return 0;
    } else {
        memcpy(p_data, temp, len);
    }

    return len;
}


uint16_t iot_data_info_get(uint8_t *p_data, uint16_t len) {
    #if 1
    time_t timestamp = get_timestamp();

    if(NULL == p_data) {
        return 0;
    } else {
        struct tm * t = localtime(&timestamp);
        uint8_t offs = 0;

        commSemaphoreTake();
        p_data[offs++] = 0;
        p_data[offs++] = t->tm_year - 100;
        p_data[offs++] = t->tm_mon + 1;
        p_data[offs++] = t->tm_mday;
        p_data[offs++] = t->tm_hour;
        p_data[offs++] = t->tm_min;
        p_data[offs++] = t->tm_sec;
        commSemaphoreGive();
    }
    
    return len;
    #else 
    time_t timestamp = get_rtc_timestamp();

    if(NULL == p_data || !rtc_sync_over_net()) {
        return 0;
    } else {
        struct tm * t = localtime(&timestamp);
        uint8_t offs = 0;

        p_data[offs++] = 0;
        p_data[offs++] = t->tm_year - 100;
        p_data[offs++] = t->tm_mon + 1;
        p_data[offs++] = t->tm_mday;
        p_data[offs++] = t->tm_hour;
        p_data[offs++] = t->tm_min;
        p_data[offs++] = t->tm_sec;
    }

    return len;
    #endif    
}


uint16_t iot_param_conf_get(uint8_t *p_data, uint16_t len) {
    uint8_t temp[VR_LEN] = {0x01, 0x02, 0x03};
    if(NULL == p_data) {
        return 0;
    } else {
        memcpy(p_data, temp, len);
    }

    return len;
}

uint16_t exbat_stat_get(uint8_t *p_data, uint16_t len) {
    if(NULL == p_data) {
        return 0;
    } else {
        commSemaphoreTake();
        memcpy(p_data, &exbatt_stat, len);
        commSemaphoreGive();
    }

    return len;
}


/* comunication data table list */
co_data_t data_tbl[] = {
    /* 电控软硬件版本号 */
    {EMU_VERSION,                       VR_LEN,                     false,      econ_version_update,                         econ_version_get},
    /* 仪表软硬件版本号 */
    {CO_VERSION,                        VR_LEN,                     false,      co_version_update,                           co_version_get},
    /* 电池软硬件版本号 */
    {BATT_VERSION,                      VR_LEN,                     false,      batt_version_update,                         batt_version_get},
    /* 蓝牙软硬件版本号 */
    {BLE_VERSION,                       VR_LEN,                     false,      ble_version_update,                          ble_version_get},
    /* 主电序列号 */
    {BATT_SEQNUM,                       SEQNUM_LEN,                 false,      batt_seqnum_update,                          batt_seqnum_get},
    /* 备电序列号 */
    {BACKUP_BATT_SEQNUM,                SEQNUM_LEN,                 false,      backup_batt_seqnum_update,                   backup_batt_seqnum_get}, 
    /* 电控序列号 */
    {EMU_SEQNUM,                        SEQNUM_LEN,                 false,      econ_seqnum_update,                          econ_seqnum_get}, 
    /* 仪表序列号 */
    {CO_SEQNUM,                         SEQNUM_LEN,                 false,      co_seqnum_update,                            co_seqnum_get},
    /* 整机客制SN */
    {CO_CUST_SN,                        SEQNUM_LEN,                 false,      co_cust_seqnum_update,                       co_cust_seqnum_get},
    /* 电机控制器信息1 */
    {EMU_INFO1,                         EMU_INFO1_LEN,              false,       emu_info1_update,                           emu_info1_get},
    /* 电机控制器信息1 */
    {EMU_INFO2,                         EMU_INFO2_LEN,              false,       emu_info2_update,                           emu_info2_get},
    /* 车端系统参数(0x3103) */
    {BIKE_SYSTEM_INFO,                  BIKE_SYSTEM_INFO_LEN,        false,       bike_system_info_update,                    bike_system_info_get},
    /* 电机控制器状态信息1 */
    {EMU_STAT_INFO1,                    EMU_STAT_INFO1_LEN,         false,       econ_stat_info1_update,                     econ_stat_info1_get},
    /* 电机控制器状态信息2（0x310B） */
    {EMU_STAT_INFO2,                    EMU_STAT_INFO2_LEN,         false,       econ_stat_info2_update,                     econ_stat_info2_get},
    /* 电机控制器状态信息3（0x310C） */
    {EMU_STAT_INFO3,                    EMU_STAT_INFO3_LEN,         false,       emu_stat_info3_update,                      econ_stat_info3_get},
    /* 软件 eeprom 版本号（0x310D） */
    {EMU_EPPR_VR,                       EMU_EPPR_VR_LEN,            false,       emu_eppr_vr_update,                         emu_eppr_vr_get},
    /* 电池容量信息（0x3300）*/
    {BATT_CAPACITY_INFO,                BATT_CAPACITY_INFO_LEN,     false,       batt_capacity_info_update,                  batt_capacity_info_get},
    /* 备电池容量信息（0x5300）*/
    {BACKUP_BATT_CAPACITY_INFO,         BATT_CAPACITY_INFO_LEN,     false,       backup_batt_capacity_info_update,           backup_batt_capacity_info_get},
    /* 电池运行状态信息（0x3301） */
    {BATT_RUN_STATUS_INFO,              BATT_RUN_STATUS_INFO_LEN,   false,       batt_run_status_info_update,                batt_run_status_info_get},
    /* 备电池运行状态信息（0x5301） */
    {BACKUP_BATT_RUN_STATUS_INFO,       BATT_RUN_STATUS_INFO_LEN,   false,       backup_batt_run_status_info_update,         backup_batt_run_status_info_get},
    /* 电池充电状态信息（0x3302） */
    {BATT_CHARGE_STATUS_INFO,           BATT_CHARGE_STATUS_INFO_LEN,   false,    batt_charge_status_info_update,             batt_charge_status_info_get},
    /* 备电池充电状态信息（0x5302） */
    {BACKUP_BATT_CHARGE_STATUS_INFO,    BATT_CHARGE_STATUS_INFO_LEN,   false,    backup_batt_charge_status_info_update,      backup_batt_charge_status_info_get},
    /* 电池电芯电压（0x330A） */
    {BATT_CELL_VOLT_INFO,               BATT_CELL_VOLT_INFO_LEN,       false,    batt_cell_volt_info_update,                 batt_cell_volt_info_get},    
    /* 电池电芯电压（0x530A） */
    {BACKUP_BATT_CELL_VOLT_INFO,        BATT_CELL_VOLT_INFO_LEN,    false,       backup_batt_cell_volt_info_update,          backup_batt_cell_volt_info_get},
    /* 电池状态信息(0x330E) */
    {BATT_STATUS_INFO,                  BATT_STATUS_INFO_LEN,       false,       batt_status_info_update,                    batt_status_info_get},
    /* 电池状态信息(0x530E) */    
    {BACKUP_BATT_STATUS_INFO,           BATT_STATUS_INFO_LEN,       false,       backup_batt_status_info_update,             backup_batt_status_info_get},
    /* 小电池（锂电池）状态（0x5101） */    
    {LBATT_STATUS_INFO,                 LBATT_STATUS_INFO_LEN,      false,       lbatt_status_info_update,                   lbatt_status_info_get},
    
    /* 周期型，若未周期上报该数据项代表充电器未接入(0x3500) */
    {CHARGER_INFO,                      CHARGER_INFO_LEN,           false,       charger_info_update,                        charger_info_get},
    /* 电子锁状态信息(0x3602) */
    {ELOCK_INFO,                        ELOCK_INFO_LEN,             false,       elock_info_update,                          elock_info_get},
    /* 仪表系统参数(0x3201) */
    {CO_INFO,                           CO_INFO_LEN,                false,       co_info_update,                             co_info_get},
    /* 电控故障码 */
    {ECON_FAULT_INFO,                   FAULT_INFO_LEN,             false,      econ_fault_info_update,                     econ_fault_info_get},
    /* 电池故障码 */
    {BATT_FAULT_INFO,                   FAULT_INFO_LEN,             false,      batt_fault_info_update,                     batt_fault_info_get},
    /* 备电池故障码 */
    {BACKUP_BATT_FAULT_INFO,            FAULT_INFO_LEN,             false,      backup_batt_fault_info_update,              backup_batt_fault_info_get},
    /* 充电器故障码 */
    {CHARGER_FAULT_INFO,                FAULT_INFO_LEN,             false,      charger_fault_info_update,                  charger_fault_info_get},
    /* 电子锁故障码 */
    {ELOCK_FAULT_INFO,                  FAULT_INFO_LEN,             false,      elock_fault_info_update,                    elock_fault_info_get},
    /* 仪表密码鉴权状态（0x32A2） */
    {CO_PWD_AUTH,                       CO_PWD_AUTH_LEN,            false,      co_pwd_auth_update,                         co_pwd_auth_get},
    /* 小电池充电状态（0x32A3） */
    {LBATT_CHG_STAT,                    LBATT_CHG_STAT_LEN,         false,      lbatt_chg_stat_update,                      lbatt_chg_stat_get},
    
    {BLE_MAC,                           BLE_MAC_LEN,                false,      ble_mac_update,                             ble_mac_get},
    /* BLE连接状态（0x3402） */
    {BLE_STATUS,                        BLE_STATUS_LEN,             false,      ble_status_update,                          ble_status_get},
    
    {IOT_FW_VERSION,                    IOT_FW_VERSION_LEN,         true,       iot_fw_version_update,                      iot_fw_version_get},
    
    {IOT_NET_STATUS,                    IOT_NET_STATUS_LEN,         true,       iot_net_status_update,                      iot_net_status_get},
    
    {IOT_GNSS_STATUS_INFO,              IOT_GNSS_STATUS_INFO_LEN,   true,       iot_gnss_status_info_update,                iot_gnss_status_info_get},
    
    {IOT_STATUS_INFO,                   IOT_STATUS_INFO_LEN,        true,       iot_status_info_update,                     iot_status_info_get},
    
    {IOT_SIM_INFO,                      IOT_SIM_INFO_LEN,           true,       iot_sim_info_update,                        iot_sim_info_get},
    
    {IOT_ALARM_INFO,                    IOT_ALARM_INFO_LEN,         false,      iot_alarm_info_update,                      iot_alarm_info_get},
    
    {IOT_INSTRUCT_CONF,                 IOT_INSTRUCT_CONF_LEN,      false,      iot_instruct_conf_update,                   iot_instruct_conf_get},
    
    {IOT_PARAM_CONF,                    IOT_PARAM_CONF_LEN,         false,      iot_param_conf_update,                      iot_param_conf_get},
    
    {IOT_SOUND_CONF,                    IOT_SOUND_CONF_LEN,         false,      iot_sound_conf_update,                      iot_sound_conf_get},
    /* IOT 时间信息（0x5210） */
    {IOT_DATE_INFO,                     IOT_DATE_INFO_LEN,          true,       NULL,                                       iot_data_info_get},
    /* 外电状态实时信息 （0x5102） */
    {EXBAT_STATUS_INFO,                 EXBAT_STATUS_INFO_LEN,      false,      exbat_stat_update,                          exbat_stat_get},
};


static int ota_read(void *data, int len)
{
    return bsp_uart_read(comm_uart_id, data, len);
}
                

static int ota_write(void *data, int len)
{
    return bsp_uart_itwrite(comm_uart_id, data, len);
}


/**
 * @brief 创建仪表通信任务
 * 
 * @return * void 
 */
void qltask_comm_start(void)
{
    ota_initize(ota_read, ota_write, getms);
    if(pdPASS !=  xTaskCreate(co_comm_task, "co_comm", 4 * 1024, NULL, osPriorityNormal, &cohb_handle))
    {
        log_e("co_comm_task create failed\r\n");
        Error_Handler();
    }
}   


/**
 * @brief 仪表通信任务
 * 
 * @param param 
 * @return * void 
 */
static void co_comm_task(void *param)
{
    bool is_ota = false;
    ssize_t len = 0;

    uint8_t data[128] = {0};
    utils_time_t ota_timer = {0};

    while(1)
    {
        if(tbox_ota_flag == 1) {
            is_ota = 1;
            tbox_ota_flag = 0;
            utils_time_countdown_ms(&ota_timer, 300*1000);  // 设置升级超时时间300s
        }
        
        /* 消息队列为空，并且仪表关机,任务空闲 */
        if (list_empty(&msg_list) && (0 == comm_info.step) && WORK_MODE_SLEEP == misc_get_work_mode())
            comm_info.is_comm_task_idle = true;
        else
            comm_info.is_comm_task_idle = false;   


        //当ota升级时，不应在此处读取仪表数据，并且暂时停止向仪表发送心跳。待升级完毕后恢复。
        if (!is_ota) {  /* normal mode, send comcu heartbeat and parser command AT+OTASTR */
            len = bsp_uart_read(comm_uart_id, (void *)data, 128);

            for (uint16_t i = 0; i < len; i++) {
                ota_process(&is_ota, data[i]);
                if (!is_ota) {
                    // data_send_process();
                    data_recv_process(data[i]);
                } else {
                    utils_time_countdown_ms(&ota_timer, 300*1000);  // 设置升级超时时间300s
                    break;
                }
            }

            len = 0;
            if (WORK_MODE_SLEEP != misc_get_work_mode()) {
                // 增加sn同步逻辑、协mcu版本获取逻辑
                sync_sn_from_comcu();
                sync_co_version_from_comcu();
                sync_bt_version_from_comcu();
                sync_econ_version_from_comcu();
                sync_eeprom_version_from_comcu();
                sync_blemac_from_comcu();
                sync_batt_version_from_comcu();
                send_heartbeat();
            }
            data_send_process();
            osDelay(100);
        } else { /* ota process, when timeout or ota fail, return to normal mode */
            ota_process(&is_ota, 0);
            if(utils_time_is_expired(&ota_timer)) {
                is_ota = false;
                tx_buf_clr(comm_uart_id);
            }
            osDelay(10);
        }

        bsp_wdt_feed();
    }
}


/**
 * @brief 仪表数据发送函数
 * 
 * @return * void 
 */
static void data_send_process(void)
{
    static msg_node_t* msg_node = NULL;

    switch(comm_info.step) {
        case 0:
            if (!list_empty(&msg_list)) {
                comm_info.step = 1;    
            }
            break;

        case 1:
            msg_node = list_first_entry(&msg_list, msg_node_t, list);
            bsp_comm_write(msg_node->data, msg_node->len);
            if (0 == msg_node->timeout) {
                // 发送响应, 不用等
                comm_info.run_times = 0;
                comm_info.step = 0;
                first_cmd_dequeue(true);
                break;
            } else {
                // 发送普通命令, 要等待
                utils_time_countdown_ms(&comm_info.timer, msg_node->timeout);  
                comm_info.run_times++;
                comm_info.step ++;
            }
            break;            

        case 2:
            if (utils_time_is_expired(&comm_info.timer)) {
                if (comm_info.run_times > msg_node->retry) {
                    log_w("Receive timeout, fail to send out data.");

                    comm_info.run_times = 0;
                    comm_info.step = 0;

                    if (msg_node->cb)
                        msg_node->cb(true);

                    first_cmd_dequeue(true);
                    break;
                } else {
                    log_w("Send data fail, retry times: %d out of %d.\r\n", comm_info.run_times, msg_node->retry);
                    comm_info.step --;
                }
            }
            break;
        default:
            comm_info.step = 0;
            break;
            
    }

}


/**
 * @brief 消息入列
 * 
 */
static int msg_enqueue(uint8_t *data, uint32_t data_len, int32_t timeout, uint8_t retry, cb_t cb)
{
    if (NULL == data || 0 == data_len) {
        return -EINVAL;
    }

    msg_node_t* msg_node = comm_malloc(sizeof(msg_node_t));
    if (NULL == msg_node) {
        log_w("Fail to allocate enough memory for msg node. File:%d, Function:%d, line:%d\r\n", __FILE__, __func__, __LINE__);
        return -ENOMEM;
    }

    memset(msg_node, 0, sizeof(msg_node_t));

    msg_node->len = data_len;
    msg_node->retry = retry;
    msg_node->timeout = timeout;
    msg_node->data = (uint8_t *)comm_malloc(msg_node->len);
    msg_node->cb = cb;
    if (NULL == msg_node->data) {
        comm_free(msg_node);
        log_w("Fail to allocate enough memory for msg node data. File:%d, Function:%d, line:%d\r\n", __FILE__, __func__, __LINE__);
        return -ENOMEM;
    }    

    memcpy(msg_node->data, data, data_len);
    list_add_tail(&msg_node->list, &msg_list);
    
    return SUCC;
}


/**
 * @brief 收到ACK报文后，消息出列
 * 
 * @return * void 
 */
static void parse_hook(void)
{
   if (list_empty(&msg_list))
       return;
  
   msg_node_t *msg_node = list_first_entry(&msg_list, msg_node_t, list);

   if (msg_node->cb != NULL)
       msg_node->cb(false);
    
    first_cmd_dequeue(true);
}


/**
 * @brief 控制发送给仪表的心跳频率
 * 
 * @return * void 
 */
static void send_heartbeat(void)
{
    static uint32_t start_time = 0;
    static uint64_t send_time = 0;
    static bool is_first_time = true;

    /* 配置参数时，自动触发一次心跳 */
    if(cfg_trig_heartbeat) {
        cfg_trig_heartbeat = 0;

        osDelay(100);
        co_data_send(1, INFO_CLASS, DAT_RPT_ID, NULL, NULL, NULL);
    }

    /* 开机前十秒高频发送心跳 */
    if (!bsp_ms_is_timeout(start_time, HIGH_FREQ_DURATION)) {
        if (bsp_ms_is_timeout(send_time, SEND_INTERVAL_PON)) {
          
            if (is_first_time) {
                start_time = getms();
                is_first_time = false;
            }          
            co_data_send(1, INFO_CLASS, DAT_RPT_ID, NULL, NULL, NULL);
            send_time = getms();
            
        }

        return;
    }

    if(bsp_ms_is_timeout(send_time, SEND_INTERVAL)) {
        send_time = getms();
        co_data_send(1, INFO_CLASS, DAT_RPT_ID, NULL, NULL, NULL);
    }
}


/**
 * @brief 数据接收处理函数
 * 
 */
static void data_recv_process(uint8_t data)
{
    static uint8_t recv_time = 0;
     
    if (!co_data_parse(data)) {
        if (bsp_ms_is_timeout(recv_time, CO_MCU_HB_POWEROFF_INTERVAL)) {
            recv_time = bsp_get_ms_since_boot();
            //log_e("Hearbeat data received timeout...");
        }
    } else {
        recv_time = bsp_get_ms_since_boot();
    }
}


/**
 * @brief 从仪表同步SN
 */
static void sync_sn_from_comcu(void)
{
    static utils_time_t sync_time = {0};
    char sn[SN_MAX_SIZE] = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        tbox_get_sn(sn, sizeof(sn));
        if (strlen(sn) <= 0\
            || strlen((char *)econ_sn) <= 0\
            || strlen((char* )batt_sn) <= 0)
        {
            uint16_t key[] = {CO_CUST_SN, EMU_SEQNUM, BATT_SEQNUM};
            co_key_add(key, ARRAY_COUNT(key));
        }

        if (is_backup_batt_insert()\
            && strlen((char *)backup_batt_sn) <= 0)
        {
            uint16_t key[] = {BACKUP_BATT_SEQNUM};
            co_key_add(key, ARRAY_COUNT(key));
        }
    }
}


/* 同步蓝牙MAC */
static void sync_blemac_from_comcu(void)
{
    static utils_time_t sync_time = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        if (strlen((char *)ble_mac) <= 0)
        {
            uint16_t key = BLE_MAC;

            co_key_add(&key, 1);
        }
    }
}


/* 同步仪表版本 */
static void sync_co_version_from_comcu(void)
{
    static utils_time_t sync_time = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        if (strlen(co_version.soft_version) <= 0)
        {
            uint16_t key = CO_VERSION;
            co_key_add(&key, 1);
        }
    }
}


/* 同步蓝牙版本 */
static void sync_bt_version_from_comcu(void)
{
    static utils_time_t sync_time = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        if (strlen(bt_version.soft_version) <= 0)
        {
            uint16_t key = BLE_VERSION;
            co_key_add(&key, 1);
        }
    }
}


/* 同步电控版本 */
static void sync_econ_version_from_comcu(void)
{
    static utils_time_t sync_time = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        if (strlen(econ_version.soft_version) <= 0 || strlen(econ_version.hw_version) <= 0)
        {
            uint16_t key = EMU_VERSION;
            co_key_add(&key, 1);
        }
    }
}


/* 同步eeprom版本 */
static void sync_eeprom_version_from_comcu(void)
{
    static utils_time_t sync_time = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        if (strlen(eeprom_version) <= 0)
        {
            uint16_t key = EMU_EPPR_VR;
            co_key_add(&key, 1);
        }
    }  
}


/* 同步电池版本 */
static void sync_batt_version_from_comcu(void)
{
    static utils_time_t sync_time = {0};

    if (utils_time_is_expired(&sync_time))
    {
        utils_time_countdown_ms(&sync_time, 10000);
        if (strlen(batt_version.soft_version) <= 0)
        {
            uint16_t key = BATT_VERSION;
            co_key_add(&key, 1);
        }
    }  
}


/* 解析来自仪表的数据 */
static uint8_t co_data_parse(uint8_t data)
{
    static uint16_t cnt = 0;
    static uint8_t step = SYNC1;
    static uint16_t payload_len = 0;
    static uint16_t msg_type = 0;
    static uint8_t payload[4096] = {0};
    static uint32_t recv_time = 0;
    static int8_t idx = 1;
    uint8_t res = 0;
    
    if(bsp_ms_is_timeout(recv_time, 3000)) {
        step = SYNC1;
        memset(payload, 0, cnt);
        cnt = 0;
        idx = 1;
        msg_type = 0;
    }
    recv_time = getms();

    switch (step)
    {
    case SYNC1:
        if(data == 0x7E) {
            memset(payload, 0, cnt);
            cnt = 0;
            idx = 1;
            msg_type = 0;
            step = SYNC2; 
        } 
        break;
    
    case SYNC2:
        if(data == 0x62) {
            step = ID;
        } else {
            step = SYNC1;
        }
        break;

    case ID:  /* (class << 8) | id */
        msg_type |= data << (idx * 8);
        payload[cnt++] = data;
        idx--;
        if(idx >= 0) {
            break;
        } else {
            step = LENL;
        }
        break;

    case LENL:
        payload_len = data;
        payload[cnt++] = data;
        step = LENH;
        break;

    case LENH:
        payload_len |= (data << 8);
        payload[cnt++] = data;
        step = PAYLOAD;
        break;

    case PAYLOAD:       
        payload[cnt++] = data;
        if (cnt >= payload_len + CLASS_SIZE + ID_SIZE + PAYLOAD_LEN_SIZE) {
            step = CRC16;
        }
        
        break;

    case CRC16:
        payload[cnt++] = data;
        
        if (cnt >= payload_len + CLASS_SIZE + ID_SIZE + PAYLOAD_LEN_SIZE + CRC16_SIZE) {
            if (stdlib_get_crc16_xmodem(payload, cnt) == 0) { 
                step = PARSE;
            } else {
                step = SYNC1;
                break;
            }
        } else {
            break;
        }

    case PARSE:
        //log_d("Receive data from co-mcu, msg_type:0x%04x\r\n", msg_type); 
        if (((INFO_CLASS << 8) | DAT_RPT_ID) == msg_type) {  
            hb_parse(&payload[4], payload_len);
        } else if (((INFO_CLASS << 8) | DAT_POLL_ID) == msg_type) {
            poll_parse(&payload[4], payload_len);  
        } else if (CFG_CLASS  == (msg_type >> 8)) { 
            cfg_parse((msg_type & 0xff), &payload[4], payload_len);  
            cfg_trig_heartbeat = 1;
        }  else if (0x3701 == msg_type) {                                     /* 仪表让iot重启 */
            tbox_system_reboot(0);            
        } else {
            parse_hook();
        }
        
        res = 1;
        step = SYNC1; 
        break;
       
    default:
        break;
    }
    return res;
}



/**
 * @brief 协议打包并执行发送函数函数，有三种不同的打包类型
 *
 * @param method 0:主动查询报文打包 1:周期心跳报文打包 2:响应主动查询的心跳报文打包 3：自定义协议报文组装，需要提供数据指针和长度
 * @param id
 * @param data   负载数据指针，设为NULL代表忽略
 * @param cnt    负载数据长度
 * @param cb     发送成功回调函数，设为NULL代表忽略
 */
static int co_data_send(uint8_t method, uint8_t class, uint8_t id, uint8_t *data, uint16_t cnt, cb_t cb)
{
    uint8_t heartbeat[256] = {0x7E, 0x62, class, id, 0x00, 0x00};
    uint8_t *payload = &heartbeat[HB_HEADER_SIZE];
    int ret = 0;
    uint16_t crc = 0;
    uint16_t payload_len = 0;
    uint32_t recv_len = 0;

    /* 根据是周期上报还是主动上报，选择不同的数据进行心跳帧组装 */
    if (0 == method) {
        for(int i = 0; i < ARRAY_COUNT(temp_tbl); i++) {
            for(int j = 0; j < ARRAY_COUNT(data_tbl); j++) {
                if (data_tbl[j].key == temp_tbl[i]) {
                    memcpy(payload, &data_tbl[j].key, sizeof(data_tbl[j].key));
                    payload += 2;
                    payload_len += 2;
                    break;
                }
            }
        }
    } else if(1 == method) {
        for(int i = 0; i < ARRAY_COUNT(data_tbl); i++) {
            if (data_tbl[i].send) {
                memcpy(payload, &data_tbl[i].key, sizeof(data_tbl[i].key));
                payload += sizeof(data_tbl[i].key);
                payload_len += sizeof(data_tbl[i].key);

                memcpy(payload, &data_tbl[i].len, sizeof(data_tbl[i].len));
                payload += sizeof(data_tbl[i].len);
                payload_len += sizeof(data_tbl[i].len);

                recv_len = data_tbl[i].get(payload, data_tbl[i].len);
                payload += recv_len;
                payload_len += recv_len;
            }
        }
    } else if(2 == method) {
        for(int i = 0; i < ARRAY_COUNT(temp_tbl); i++) {
            for(int j = 0; j < ARRAY_COUNT(data_tbl); j++) {
                if (data_tbl[j].key == temp_tbl[i]) {
                    memcpy(payload, &data_tbl[j].key, sizeof(data_tbl[j].key));
                    payload += sizeof(data_tbl[j].key);
                    payload_len += sizeof(data_tbl[j].key);

                    memcpy(payload, &data_tbl[j].len, sizeof(data_tbl[j].len));
                    payload += sizeof(data_tbl[j].len);
                    payload_len += sizeof(data_tbl[j].len);

                    recv_len = data_tbl[j].get(payload, data_tbl[j].len);
                    payload += recv_len;
                    payload_len += recv_len;
                    break;
                }
            }
        }
    } else {
        if(NULL != data && 0 != cnt) {
            memcpy(payload, data, cnt);
            payload_len += cnt;
        }
    }

    if (HB_HEADER_SIZE + payload_len < sizeof(heartbeat)) {
        memcpy(&heartbeat[SYNC1_SIZE + SYNC2_SIZE + CLASS_SIZE + ID_SIZE], &payload_len, sizeof(payload_len));
        crc = stdlib_get_crc16_xmodem(&heartbeat[SYNC1_SIZE + SYNC2_SIZE], HB_HEADER_SIZE - 2 + payload_len);
        crc = ((crc << 8) & 0xFF00) | ((crc >> 8) & 0xFF);
        memcpy(&heartbeat[HB_HEADER_SIZE + payload_len], &crc, sizeof(crc));
    } else {
        log_e("Out of data buff, abort...");
        return -ENOMEM;
    }
    
    ret = msg_enqueue(heartbeat, HB_HEADER_SIZE + payload_len + 2, 500, 2, cb);

    return ret;
}


/* 根据key值添加触发上报类型的数据 */
static bool co_hearbeat_add(uint16_t key)
{
    bool res = false;
    int16_t idx = -1;
    for(int j = 0; j < sizeof(data_tbl)/sizeof(data_tbl[0]); j++) {
        if(key == data_tbl[j].key) {
            while(0 != temp_tbl[++idx]);
            temp_tbl[idx] = key;
            res = true;
        }
    }
    return res;
}


/* 响应包发送完心跳之后删除有关key值 */
static void co_hearbeat_del(void)
{
    memset(temp_tbl, 0, sizeof(temp_tbl)/sizeof(temp_tbl[0]));
}


/* 添加主动查询的key */
void co_key_add(uint16_t* key, uint16_t len) {
    for (int i = 0; i < len; i++) {
        co_hearbeat_add(key[i]);
    }
    if (*key == EXBAT_STATUS_INFO)
        co_data_send(0, INFO_CLASS, DAT_POLL_ID, NULL, NULL, sync_pwr_cb);
    else 
        co_data_send(0, INFO_CLASS, DAT_POLL_ID, NULL, NULL, NULL);
    co_hearbeat_del();
}


/**
 * @brief 获取外电回调
 * 
 * @param is_timeout 
 * @return * void 
 */
static void sync_pwr_cb(bool is_timeout)
{
    if (is_timeout)
        memset(&exbatt_stat, 0, sizeof(exbatt_stat));
    return;
}


static void co_send_ack(uint16_t msg_type)
{
    uint16_t ack_crc = 0;
    uint8_t ack[] = {0x7E, 0x62, ACK_CLASS, ACK_ID, 0x03, 0x00, ((msg_type >> 8) & 0xFF), msg_type & 0xFF, 0x00, 0xFF, 0xFF};

    ack_crc = stdlib_get_crc16_xmodem(ack + 2, sizeof(ack) - 4);      // crc without head(2B) and crc(2B)
    ack[HB_HEADER_SIZE + 3] = ((ack_crc >> 8) & 0xFF) ;
    ack[HB_HEADER_SIZE + 4] = (ack_crc & 0xFF);

    if(!bsp_uart_itwrite(comm_uart_id, (void *)&ack, sizeof(ack))) {
        log_e("fail to send out ack");
    } 
#ifdef __DEBUG
    log_d("co_send_ack: ");
    for (int i = 0; i < sizeof(ack); i++)
    {
        log_d("0x%02x ", ack[i]);
    }
#endif
}


static void co_send_nack(uint16_t msg_type, uint8_t err_code)
{
    uint16_t nack_crc = 0;
    uint8_t nack[] = {0x7E, 0x62, ACK_CLASS, ACK_ID, 00, 03, ((msg_type >> 8) & 0xFF), msg_type & 0xFF, err_code, 0xFF, 0xFF};
    nack_crc = stdlib_get_crc16_xmodem(nack + SYNC1_SIZE + SYNC2_SIZE, sizeof(nack) - SYNC1_SIZE - SYNC2_SIZE);
    nack[HB_HEADER_SIZE + 3] = ((nack_crc >> 8) & 0xFF) ;
    nack[HB_HEADER_SIZE + 4] = (nack_crc & 0xFF);

    if(!bsp_uart_itwrite(comm_uart_id, (void *)&nack, sizeof(nack))) {
        log_e("fail to send out nack");
    }   
#ifdef __DEBUG
    log_d("co_send_ack: ");
    for (int i = 0; i < sizeof(nack); i++)
    {
        log_d("0x%02x ", nack[i]);
    }
#endif
}



/**
 * @brief 消息出列
 * 
 * @param is_rest 
 * @return * void 
 */
static void first_cmd_dequeue(bool is_rest)
{
    struct list_head *list_ptr, *n= NULL;
    list_for_each_safe(list_ptr, n, &msg_list) {
        msg_node_t *msg_node = list_entry(list_ptr, msg_node_t, list);
        if (NULL != msg_node) {
            comm_free(msg_node->data);
            list_del(list_ptr);
            comm_free(msg_node);
            msg_node = NULL; // 清空
            break;
        }
    }

    if (is_rest) {
        comm_info.step = 0;
        comm_info.run_times = 0;
        utils_time_init(&comm_info.timer);
    }
}


/** 判断仪表是否关机超时 */
uint32_t co_mcu_timeout(void)
{
    return (getsec() - co_heartbeat_last_recv_tick);
}


/* 解析来自仪表的心跳 */
static void hb_parse(uint8_t* payload, uint16_t len)
{
    static uint8_t a = 0;
    a++;
    uint8_t *start = payload;
    uint8_t data[256] = {0};

    while(payload < start + len) {
        uint16_t key = (payload[1] << 8) | payload[0];
        uint8_t  plen = payload[2];
        for(int i = 0; i < sizeof(data_tbl)/sizeof(data_tbl[0]); i++) {
            if (key == data_tbl[i].key) {
                memcpy(data, &payload[3], plen);
                data_tbl[i].update(data, plen);
                break;
            }
        }
        payload += 3 + plen;
    }

    /* 记录最后接收心跳包时间，判断仪表开关机 */
    co_heartbeat_last_recv_tick = getsec();
    
}


/* 判断仪表开关机(上电+can报文=开机) */
bool is_ebike_mcu_off(void)
{
    if ((0 == co_heartbeat_last_recv_tick) || timeout_sec(co_heartbeat_last_recv_tick, CO_MCU_HB_POWEROFF_INTERVAL)) {
        return true;
    }
    else 
        return false;
}


/* 判断ebike是否在骑行 */
bool is_ebike_riding(void)
{
    return !is_ebike_mcu_off() && get_ebike_speed() > 0;
}


/* 获取ebike助力挡位 */
int8_t get_ebike_pwr_lvl(void)
{
    if (electric_vehicle_info2.pwr_lvl_is_valid)
        return electric_vehicle_info2.pwr_lvl;
    else 
        return -EPERM;
}


/* 获取ebike当前车速 */
float get_ebike_speed(void)
{
    if (co_motor_ctrl_info_1.speed_valid)
        return co_motor_ctrl_info_1.speed;
    else 
        return -EPERM;
}


static void poll_parse(uint8_t* payload, uint16_t len)
{
    uint16_t key = 0;
    bool rd_succ = false;

    /* 根据响应包的key添加心跳要发送的信息 */
    for(int i = 0; i < len/2; i++) {
        key = (payload[2*i + 1] << 8) | payload[2*i];

        /* 这么做的目的是为保证但凡有收到一个key就会立即发一个心跳 */
        if(false == rd_succ) {
            rd_succ = co_hearbeat_add(key);
        } else {
            co_hearbeat_add(key);
        }
    }

    /* 成功发ack，并立即发一包心跳；失败发nack */
    if(true == rd_succ) {
        co_data_send(2, INFO_CLASS, DAT_RPT_ID, NULL, NULL, NULL);
        co_send_ack(((INFO_CLASS << 8) | DAT_POLL_ID));
        rd_succ = false;
    } else {
        co_send_nack(((INFO_CLASS << 8) | DAT_POLL_ID), 1);
        return;
    }

    /* 心跳发送完毕之后删除key */
    co_hearbeat_del();
}


//static unsigned short crc16_cumulative(const unsigned char *buf, unsigned int count, unsigned short init_crc)
//{
//    unsigned short crc = init_crc;
//    int i;
//
//    while(count--) {
//        crc = crc ^ *buf++ << 8;
//
//        for (i = 0; i < 8; i++) {
//            if (crc & 0x8000) {
//                crc = crc << 1 ^ 0x1021;
//            } else {
//                crc = crc << 1;
//            }
//        }
//    }
//
//    return crc;
//}


static void co_respond_cfg_data(uint16_t msg_type, uint8_t *payload, uint16_t len)
{
    if(payload == NULL)
        return;

    uint16_t respond_crc = 0;
    uint16_t offset = 0;
    uint8_t  ack_head[] = {0x7E, 0x62, ((msg_type >> 8) & 0xFF), msg_type & 0xFF, len & 0xFF, (len >> 8) & 0xFF};

    uint8_t *ack = qlmalloc(len + HB_FIX_SIZE);
    if (NULL == ack) {
        return;
    }

    memcpy(&ack[offset], ack_head, sizeof(ack_head));
    offset += sizeof(ack_head);
    memcpy(&ack[offset], payload, len);
    offset += len;

    // cal the crc without the head bytes
    respond_crc = stdlib_get_crc16_xmodem(ack + SYNC1_SIZE + SYNC2_SIZE, offset - SYNC1_SIZE - SYNC2_SIZE);
    ack[offset++] = (respond_crc >> 8) & 0xFF;
    ack[offset++] = respond_crc & 0xFF;

    if(!bsp_uart_itwrite(comm_uart_id, (void *)ack, offset)) {
         log_e("fail to send out co respond head...");
    }
#ifdef __DEBUG
    log_d("co_respond_cfg_data: ");
    for (int i = 0; i < offset; i++)
    {
        log_d("0x%02x ", ack[i]);
    }
    log_d("\r\n");
#endif
    qlfree(ack);
}

uint8_t cacert_map[4] = {0};

#define bit_set(x, bit) (x[bit / 8] |= (1 << ((bit % 8))));
#define bit_chk(x, bit) (x[bit / 8] & (1 << ((bit % 8)))) ? 1 : 0
#define bit_clr(x, len) memset(cacert_map, 0, len)

server_ssl_params_t ssl = {0};
void cfg_parse(uint8_t id, uint8_t* payload, uint16_t len)
{
    int ret = 0;;

    assert(payload);

    if (id == 0x01) {           /* CFG-CO-AUD */

    }else if (id == 0x08) {     /* CFG-CO-BLE */

    }else if (id == 0x09) {     /* CFG-IOT-PROTECT */

    }else if (id == 0x10) {     /* CFG-IOT-SERVER */
        server_params_t server = {0};

        misc_server_param_get(&server);

        if(len == 0) { /* 查询服务器参数 */
            char cfg_response[66] = {0};

            strncpy(cfg_response, server.ipaddr, 64);
            memcpy(&cfg_response[64], &server.port, 2);

            // 发送CFG应答
            co_respond_cfg_data( (CFG_CLASS<<8) | id, (uint8_t *)cfg_response, sizeof(cfg_response));
        } else {
            char *server_ip = (void *)payload;
            if ( (strlen(server_ip) > 0) && (strlen(server_ip) < sizeof(server.ipaddr))) {
                ret |= 1;
            }

            unsigned short server_port = 0;
            memcpy((void *)&server_port, payload + 64, 2);
            if (server_port >= 0) {
                ret |= 2;
            }

            if(ret == 3) {
                strcpy(server.ipaddr, server_ip);
                server.port = server_port;
                server.enable = true;
                // 先返回再设置参数
                co_send_ack((CFG_CLASS << 8) | id);
                // 设置后保存测试参数
                if (0 == strcmp(server_ip, "218.17.50.142") || 0 == strcmp(server.ipaddr, "183.56.181.58")) {   /* 测试 IP默认不走SSL */
                     server.is_ssl = 0;
                } else {
                    if (strlen(misc_ssl_cacert_get()) > 0) {
                        server.is_ssl = 1;
                    }
                }
                misc_server_param_set(&server);
                log_i("update server ip and port success.[%s:%d].", server.ipaddr, server.port);
                tbox_system_reboot(0);
            } else {
                co_send_nack((CFG_CLASS << 8) | id, ret);
                log_e("update server ip and port fail[%d].", ret);
            }
        }

        return;

    }else if ( (id >= 0x11) &&  (id <= 0x30)) {     /* CFG-IOT-CA */
        if (len == 0) { /* 查询CA CRC16 */
            const char *cert = misc_ssl_cacert_get();
            uint16_t file_crc;

            file_crc = stdlib_get_crc16_xmodem((void *)cert, strlen(cert));
            /* 0错误   其他值CRC */
            co_respond_cfg_data( (CFG_CLASS<<8) | id, (uint8_t *)&file_crc, sizeof(file_crc));
        } else {    /* 设置CA file DATA */
            char ca_seq = id - 0x11;
            char *end_line = strstr((void *)payload, "END CERTIFICATE");

            if(ca_seq == 0) {
                memset(&ssl, 0, sizeof(ssl));
                // disable ssl;
                misc_server_ssl_set(0);
                misc_ssl_cacert_clear();

                bit_clr(cacert_map, sizeof(cacert_map));
            }

            // save ssl cert
            if (ca_seq >= 0) {
                if (ssl.cacert_len + len  < sizeof(ssl.cacert)) {

                    if(!bit_chk(cacert_map, ca_seq)) {
                        memcpy(ssl.cacert + ssl.cacert_len, payload, len);
                        ssl.cacert_len += len;
                        memcpy(ssl.cacert + ssl.cacert_len, "\r\n", strlen("\r\n"));
                        ssl.cacert_len += strlen("\r\n");
                    }

                    bit_set(cacert_map, ca_seq);

                    /* 非最后包 只复制数据 */
                    if(end_line == NULL) {
                        co_send_ack((CFG_CLASS << 8) | id);
                    }
                } else {
                    ret = -1;
                    co_send_nack((CFG_CLASS << 8) | id, abs(ret));

                    return;
                }
            }

            // check if the last packet of cert is detected
            if((end_line != NULL) || ( ca_seq == (0x30 - 0x11))) {
                /* 写入证书到文件 */
                if(0 !=  (ret = misc_ssl_cacert_set((char *)ssl.cacert, ssl.cacert_len))) {
                    co_send_nack((CFG_CLASS << 8) | id, abs(ret));
                    return;
                }

                co_send_ack((CFG_CLASS << 8) | id);
            }
        }

    }else {
        /* 其他指令 */
    }


}


/**
 * @brief 升级完成后返回结果
 * @param  result           My Param doc
 * @param  result_len       My Param doc
 * @return int32_t
 */
int32_t ymodem_update_result_send(char *result, uint16_t result_len)
{
    int32_t res = 0;

    tx_buf_clr(comm_uart_id);
    res = ota_write(result, result_len);
    res = ota_write(result, result_len);
    res = ota_write(result, result_len);

    return res;
}


/**
 * @brief IOT控制仪表音频播放
 * 
 * @param type 播放音频类型
 * @return int 
 */
int co_aud_cmd(enum aud_type type)
{
    if (type != AUD_TYPE_ALARM && type != AUD_TYPE_BINDING && type != AUD_TYPE_ENCLOSURE_IN && type != AUD_TYPE_ENCLOSURE_OUT && type != AUD_TYPE_FIND_BIKE)
        return -EINVAL;

    uint8_t data[IOT_CO_AUDIO_LEN] = {type};

    return co_data_send(3, IOT_CLASS, IOT_CO_AUDIO_ID, data, IOT_CO_AUDIO_LEN, NULL);
}


/**
 * @brief IOT配置仪表音效
 * 
 * @param aud_cfg 
 * @return * int 
 */
int co_aud_cfg(aud_cfg_t *aud_cfg)
{
    uint8_t data[CFG_CO_AUD_LEN] = {0};

    if (NULL == aud_cfg)
        return -EINVAL;

    memcpy(&data, aud_cfg, CFG_CO_AUD_LEN);

    return co_data_send(3, CFG_CLASS, CFG_CO_AUD_ID, data, CFG_CO_AUD_LEN, NULL);
}


/**
 * @brief IOT配置仪表音量
 * 
 * @param volume 音量大小：1-5
 * @return * int 
 */
int co_volume_cfg(int volume)
{
    uint8_t data[CFG_CO_VOLUME_LEN] = {0};

    if (volume < 1 || volume > 5)
        return -EINVAL;

    memcpy(&data, &volume, CFG_CO_VOLUME_LEN);

    return co_data_send(3, CFG_CLASS, CO_VOLUME_ID, data, CFG_CO_VOLUME_LEN, NULL);
}


/**
 * @brief 配置仪表蓝牙参数
 * 
 * @param ble_cfg 
 * @param param 0: 蓝牙感应距离，1：蓝牙无感解锁开关
 * @return * int 
 */
int co_ble_cfg(ble_cfg_t *ble_cfg, int param)
{
    uint8_t data[CFG_CO_BLE_LEN] = {0};

    if (NULL == ble_cfg)
        return -EINVAL;

    if (param == 0) {
        memcpy(&data, &ble_cfg->ble_detect_level, sizeof(ble_cfg->ble_detect_level));  
        return co_data_send(3, CFG_CLASS, CO_BLE_DISTANCE, data, sizeof(ble_cfg->ble_detect_level), NULL);
    } else {
        memcpy(&data, &ble_cfg->ble_inductiveunlock_enable, sizeof(ble_cfg->ble_inductiveunlock_enable));  
        return co_data_send(3, CFG_CLASS, CO_BLE_LOCK, data, sizeof(ble_cfg->ble_inductiveunlock_enable), NULL);
    }
}


/**
 * @brief IOT请求仪表复位
 * 
 * @return * int 
 */
int co_reset(void)
{
    return co_data_send(3, IOT_CLASS, CO_RESET_ID, NULL, 0, NULL);
}


/**
 * @brief IOT请求仪表关机
 * 
 * @return int 
 */
int co_pwr(void)
{
    return co_data_send(3, IOT_CLASS, CO_OFF_ID, NULL, 0, NULL);
}

/**
 * @brief 小电池充电状态获取 
 * @return uint8_t 
 */
uint8_t libatt_charger_status_get(void)
{
    return li_batt_status_info.charge_state;
}

/**
 * @brief 获取仪表密码鉴权状态
 * 
 * @return uint8_t 0 - 未完成密码鉴权； 1 - 已完成密码鉴权
 */
uint8_t get_auth_status(void)
{
    return co_auth_status.status;   
}


/**
 * @brief 获取备电池是否在位
 * 
 * @return true: 在位
 *         false：不在位
 */
bool is_backup_batt_insert(void)
{
    if ((0 == co_heartbeat_last_recv_tick) || timeout_sec(co_heartbeat_last_recv_tick, CO_MCU_HB_POWEROFF_INTERVAL)) {
        return false;
    }
    else {
        /* 判断是否在位 */
        if (0 == batt_charge_status_info[backup_batt].charge_s_valid)
            return false;
        else
            return true;
    }    
}


/**
 * @brief 获取备用电池充电状态
 * 
 * @return uint8_t 0 - 正在充电； 1 - 未充电； -1 - 未在位
*/
int8_t get_backup_batt_charging_status(void)
{
    if (is_backup_batt_insert())
        return batt_charge_status_info[backup_batt].charge_state;
    else
        return -1;
}


typedef enum {  
    LOCK,           /* 锁住状态 */
    UNLOCK,         /* 打开状态； */
    LOCK_BUSY,      /* 锁住忙状态 */
    UNLOCK_BUSY,    /* 打开忙状态 */
} eLockStatus_t;

/**
 * @brief 获取电子锁状态
 * 
 * @return uint8_t   0 - 电子锁未打开； 1 - 电子锁打开； 0xFF - 无效状态
 */
uint8_t get_elock_status(void)
{
    if (is_ebike_mcu_off())
        return 1;

    switch(co_lock_status.status)
    {
        case LOCK:
        case LOCK_BUSY:
            return 1;
        case UNLOCK:
        case UNLOCK_BUSY:
            return 0;
        default:
            return 0xFF;
    }
}


/**
 * @brief 判断充电器是否插入
 * 
 * @return uint8_t 0 - 未插入； 1 - 插入
 */
uint8_t is_charger_inserted(void)
{
    if (utils_time_is_expired(&charger_info.timer)\
        || charger_info.is_hard_fault\
        || charger_info.is_high_temp\
        || charger_info.is_volt_err\
        || charger_info.is_close\
        || charger_info.is_comm_timeout
        || is_ebike_mcu_off())
        return 0;
    
    return 1;
}


/**
 * @brief 获取尾灯开关状态
 * 
 * @return uint8_t  0 - 关； 1 - 开
 */
uint8_t is_rear_light_on(void)
{
    return co_status_info.tail_light;   
}


/**
 * @brief 和仪表通讯任务是否空闲
 * 
 * @return true 
 * @return false 
 */
bool is_comm_idle(void)
{
    /* 消息队列为空，并且仪表关机 */
    return comm_info.is_comm_task_idle;
}